#ifndef __SD_DRIVER_H
#define __SD_DRIVER_H

#include <avr/io.h>
#include <stdint.h>

//SD Card SPI Pin Configuration
#define sdSCK	(1<<7)
#define sdSO	(1<<6)
#define sdSI	(1<<5)
#define sdCS	(1<<4)

//SD Card PORT Info
#define sdSPI SPIC
#define sdPORT PORTC

//SD Card Clock Speeds
#define SD_SPI_HIGHSPEED 0x00 // 16MHz
#define SD_SPI_LOWSPEED 0x03

//use following macros if PD0 pin is used for Chip Select of SD
#define SD_CS_ASSERT     sdPORT.OUT &= (~sdCS)
#define SD_CS_DEASSERT   sdPORT.OUT |= sdCS

//SD commands, many of these are not used, but kept for reference if needed
#define GO_IDLE_STATE            0
#define SEND_OP_COND             1
#define SEND_IF_COND             8
#define SEND_CSD                 9
#define STOP_TRANSMISSION        12
#define SEND_STATUS              13
#define SET_BLOCK_LEN            16
#define READ_SINGLE_BLOCK        17
#define READ_MULTIPLE_BLOCKS     18
#define WRITE_SINGLE_BLOCK       24
#define WRITE_MULTIPLE_BLOCKS    25
#define ERASE_BLOCK_START_ADDR   32
#define ERASE_BLOCK_END_ADDR     33
#define ERASE_SELECTED_BLOCKS    38
#define SD_SEND_OP_COND          41   //ACMD
#define APP_CMD                  55
#define READ_OCR                 58
#define CRC_ON_OFF               59

/****************************************************************************
* Purpose:	Initializes SD Card SPI Port/Pins
* Input:	No Input
* Output:	No Output
****************************************************************************/
void sdSpiInit(void);

/****************************************************************************
* Purpose:	Sets the sd card SPI rate to 16MHz
* Input:	No Input
* Output:	No Output
****************************************************************************/
void sdSpiHighspeed(void);

/****************************************************************************
* Purpose:	Sends a single byte to SD Card
* Input:	No Input
* Output:	No Output
****************************************************************************/
uint8_t sdSpiSend(uint8_t);

/****************************************************************************
* Purpose:	Recieves a single byte from SD Card (Has to send a dummy byte)
* Input:	No Input
* Output:	No Output
****************************************************************************/
uint8_t sdSpiRecv(void);

/****************************************************************************
* Purpose:	Initializes SD Card
* Input:	No Input
* Output:	Returns SD Card Type
****************************************************************************/
uint8_t sdInit(void);

/****************************************************************************
* Purpose:	Sends a command to the SD Card
* Input:	The Command and 32bit argument
* Output:	No Output
****************************************************************************/
uint8_t sdSendCmd(uint8_t cmd, uint32_t arg);

/****************************************************************************
* Purpose:	Reads a single block from the sd card
* Input:	Number of sector to be read, pointer to buffer of length at least
*			512 bytes
* Output:	Returns 0 on success, otherwise returns response byte
****************************************************************************/
uint8_t sdReadSingleBlock(uint32_t startBlock, uint8_t * buf);

/****************************************************************************
* Purpose:	Called to initalize sd card and interpret SD_init() return value
* Input:	No Input
* Output:	Returns 0 on success, 1 on failure
****************************************************************************/
int mediaInit(void);

/****************************************************************************
* Purpose:	Wraps the SD_readsingleblockbuf function so we can pass it as
*			a function pointer to fat library
* Input:	Number of sector to be read, pointer to data buffer to write
*			data to
* Output:	Returns 0 on success, otherwise returns response byte
****************************************************************************/
int mediaRead(unsigned long sector, unsigned char *buffer);

/****************************************************************************
* Purpose:	Sets a flag to disable reading/writing to sd card and prevent
*			lockup on media removal during a read/write call. All data read
*			from sd card thereafter will be garbage
* Input:	No Input
* Output:	No Output
****************************************************************************/
void sdDisableSpi(void);

/****************************************************************************
* Purpose:	Sets a flag to enable reading/writing to sd card
* Input:	No Input
* Output:	No Output
****************************************************************************/
void sdEnableSpi(void);

#endif /* __SD_DRIVER_H */